module klang.klang.转换工厂.实例化代码.中间码_;
import 全局;
import std.conv: ·to = to;
import std.functional: ·fd = toDelegate;
import ··klang类型_ = klang.klang.类型.klang类型_;
import ··节点_ = klang.编译.语法节点.节点_;
import klang.编译.类型.类型_: 转换上下文_, 转换函数_, 输出解析器_, 程序主机接口_, 三元结果_;
import klang.编译.系统.系统_: sys;
import klang.编译.类型.枚举值.枚举值_: SK;
import klang.编译.路径.路径_: 组合路径;
import klang.编译.语法节点.节点_: 基础节点_ = 节点_, 基础令牌_ = 令牌_;
import klang.klang.工具.klang工具_: 设置节点标志, 获取源文件的程序集;
import klang.klang.语法节点.Klang节点_: 节点_ = Klang节点_, 源文件_ = Klang源文件_, 标识符_ = Klang标识符_, 版本语句_, 块_, 测试单元语句_, 变量语句_, 变量声明列表_, 变量声明_, 程序声明_, 函数声明_, 属性声明_, 属性赋值_, 结构声明节点_ = 结构声明_, 对象声明节点_ = 对象声明_, 获取源文件, 是启动函数, 合成注释_;
import klang.klang.检查.klang检查_: Klang转换支持_, 获取源文件的程序声明, 获取符号的声明类型;
import klang.klang.类型.klang类型_: 符号_ = Klang符号_, KSK, 编译选项_, 节点标志_;
import klang.编译.核心.核心_: 词典_, 整数_, 创建数组, 创建词典, 循环每个, 连接;
import klang.klang.节点工厂.Klang工厂_: 节点工厂标志_, 节点工厂_ = Klang节点工厂_;
import klang.klang.转换工厂.转换工具.Klang转换工具_: 获取输出文件名, 尝试删除扩展;
import klang.klang.转换工厂.实例化代码.类型.实例化使用类型_: 未整合的源文件_, 实例化引用标志_, 实例化引用_, 类型打印标志_, 类型打印环境_;
import klang.klang.转换工厂.实例化代码.工具.工具_: 实例化类型, 获取符号文本Id, 获取节点文本Id, 获取节点扩展, 获取节点符号, 访问节点数组, 生成分隔注释, 清除分隔距离;
import klang.klang.转换工厂.实例化代码.实例化访问.实例化访问_: 初始当前打印环境, 实例化全局变量声明, 实例化测试单元, 更新;
import klang.klang.转换工厂.实例化代码.内置函数.内置函数_: 初始内置函数 = 初始环境;
源文件_ 当前源文件;
转换上下文_ 当前上下文;
输出解析器_ 输出解析;
编译选项_ 编译选项;
节点工厂_ fc;
Klang转换支持_ K;
程序主机接口_ 主机;
词典_!(未整合的源文件_) 未整合的源文件组;
未整合的源文件_ 当前未整合的源文件;
未整合的源文件_ 未整合的泛型源文件;
dstring[] 当前包名;
词典_!(基础节点_[]) 当前方法声明;
符号_ 合并程序集符号;
dstring 当前程序集合并ID;
词典_!(实例化引用_) 项目声明的符号集合;
类型打印环境_ 当前打印环境;
未整合的源文件_[] 输出的源文件;
转换函数_!(基础节点_) 实例化代码转换(转换上下文_ ct) {
    .当前上下文 = ct;
    .输出解析 = 当前上下文.getEmitResolver();
    .fc = new 节点工厂_(节点工厂标志_.合成工厂_, 节点标志_.Synthesized);
    .K = (cast(Klang转换支持_)(输出解析.获取输出转换支持()));
    .主机 = 输出解析.获取主机();
    .编译选项 = (cast(编译选项_)(主机.获取编译选项()));
    .未整合的源文件组 = 创建词典!(未整合的源文件_)();
    .当前包名 = 创建数组!(dstring)();
    .项目声明的符号集合 = 创建词典!(实例化引用_)();
    初始内置函数(.fc, .K);
    .未整合的泛型源文件 = new 未整合的源文件_();
    return cast(转换函数_!(基础节点_))(·fd(&.转换));
}
基础节点_[] 转换(基础节点_ n) {
    .当前源文件 = 获取源文件(n);
    .转换源文件(.当前源文件);
    if ((当前源文件.标志 & 节点标志_.节点组中最后一个) != 0) {
        设置节点标志(.当前源文件, ~节点标志_.节点组中最后一个);
        if (.输出的源文件 is ··null!(未整合的源文件_[])) {
            .输出的源文件 = 创建数组!(未整合的源文件_)();
        }
        if (!未整合的泛型源文件.是空的()) {
            .追加!(未整合的源文件_)(.输出的源文件, .未整合的泛型源文件);
        }
        基础节点_[] 输出组 = 创建数组!(基础节点_)();
        foreach (未整合的源文件_ xs; .输出的源文件) {
            节点_[] 语句组 = 创建数组!(节点_)();
            if (xs.对象声明组.大小() > 0) {
                xs.对象声明组.p·循环每个((基础节点_[] vs, dstring name) {
                    if (vs.length > 0) {
                        .追加!(节点_)(语句组, 生成分隔注释("声明部分: "d));
                        .追加!(节点_)(语句组, (cast(节点_[])(vs)));
                    }
                });
            }
            if (xs.变量声明组.length > 0) {
                .追加!(节点_)(语句组, 生成分隔注释("变量部分: "d));
                .追加!(节点_)(语句组, (cast(节点_[])(xs.变量声明组)));
            }
            if (xs.语句组.length > 0) {
                .追加!(节点_)(语句组, 生成分隔注释("函数部分: "d));
                .追加!(节点_)(语句组, (cast(节点_[])(xs.语句组)));
            }
            if (xs.需要引用的.大小() > 0) {
                节点_[] 前面变量声明 = 创建数组!(节点_)();
                节点_[] 前面类型声明 = 创建数组!(节点_)();
                节点_[] 后面函数引用 = 创建数组!(节点_)();
                xs.需要引用的.p·循环每个((实例化引用标志_ V, dstring name) {
                    if (!xs.文件内存在的.具有(name)) {
                        实例化引用_ TZ = 项目声明的符号集合.获取(name);
                        if ((TZ.引用标志 & 实例化引用标志_.外部虚拟_) == 0) {
                            if ((V & 实例化引用标志_.变量声明_) != 0) {
                                if ((TZ.引用标志 & 实例化引用标志_.变量声明_) != 0) {
                                    .追加!(基础节点_)(cast(基础节点_[])(前面变量声明), TZ.变量声明语句);
                                    xs.文件内存在的.p·设置(name, V);
                                }
                                else {
                                    assert(false, "没找到变量"c);
                                }
                            }
                            else if ((V & 实例化引用标志_.类型声明_) != 0) {
                                if ((TZ.引用标志 & 实例化引用标志_.类型声明_) != 0) {
                                    .追加!(节点_)(前面类型声明, TZ.类型声明);
                                    xs.文件内存在的.p·设置(name, V);
                                }
                                else {
                                    assert(false, "没找到类型声明"c);
                                }
                            }
                            else if ((V & 实例化引用标志_.函数声明_) != 0) {
                                if ((TZ.引用标志 & 实例化引用标志_.函数声明_) != 0) {
                                    .追加!(节点_)(后面函数引用, TZ.函数声明);
                                    xs.文件内存在的.p·设置(name, V);
                                }
                                else {
                                    assert(false, "没找到函数声明"c);
                                }
                            }
                            else if ((V & 实例化引用标志_.构建声明_) != 0) {
                                if ((TZ.引用标志 & 实例化引用标志_.构建声明_) != 0) {
                                    .追加!(节点_)(后面函数引用, TZ.函数声明);
                                    xs.文件内存在的.p·设置(name, V);
                                }
                                else {
                                    assert(false, "没找到构建声明"c);
                                }
                            }
                            else if ((V & 实例化引用标志_.方法声明_) != 0) {
                                if ((TZ.引用标志 & 实例化引用标志_.方法声明_) != 0) {
                                    .追加!(节点_)(后面函数引用, TZ.函数声明);
                                    xs.文件内存在的.p·设置(name, V);
                                }
                                else {
                                    assert(false, "没找到构建声明"c);
                                }
                            }
                        }
                    }
                });
                if (前面类型声明.length > 0) {
                    if (前面变量声明.length == 0) {
                        前面类型声明 = .追加!(节点_)([生成分隔注释("引用的类型:"d)], 前面类型声明);
                        .追加!(节点_)(前面变量声明, 前面类型声明);
                    }
                    else {
                        前面变量声明 = .追加!(节点_)([生成分隔注释("引用的变量:"d)], 前面变量声明);
                        前面变量声明 = .追加!(节点_)(前面类型声明, 前面变量声明);
                        前面变量声明 = .追加!(节点_)([生成分隔注释("引用的类型:"d)], 前面变量声明);
                    }
                }
                if (前面变量声明.length > 0) {
                    语句组 = .追加!(节点_)(前面变量声明, 语句组);
                }
                if (后面函数引用.length > 0) {
                    后面函数引用 = .追加!(节点_)([生成分隔注释("引用的函数:"d)], 后面函数引用);
                    语句组 = .追加!(节点_)(语句组, 后面函数引用);
                }
            }
            if (xs != .未整合的泛型源文件) {
                源文件_ 源文件 = (cast(源文件_)(xs.整合的文件[0]));
                程序声明_ 程序集 = 获取源文件的程序集(源文件);
                .清除语句前部分隔距离(cast(基础节点_[])(语句组));
                语句组 = [fc.创建程序声明(更新!(标识符_)(fc.创建文本标识符(xs.程序名称), 程序集.名称), fc.f·创建节点数组!(节点_)(语句组, false), new 基础令牌_!(SK)(SK.右大括号))];
            }
            else {
                if (语句组.length > 0) {
                    语句组 = .追加!(节点_)([生成分隔注释("合成的泛型文件:"d, 0)], 语句组);
                    .清除语句前部分隔距离(cast(基础节点_[])(语句组));
                }
            }
            源文件_ s = fc.创建源文件(·to!(··节点_.节点数组_!(基础节点_))(fc.f·创建节点数组!(节点_)(语句组, false)));
            if (xs == .未整合的泛型源文件) {
                s.输出文件名 = .计算合成文件输出名();
            }
            else {
                s.输出文件名 = 获取输出文件名((cast(源文件_)(xs.整合的文件[0])), .主机, .编译选项, ".k2"d);
            }
            s.整合的源文件 = xs.整合的文件[0 .. $];
            .追加!(基础节点_)(输出组, s);
        }
        return 输出组;
    }
    return ··null!(基础节点_[]);
}
void 转换源文件(源文件_ n) {
    n.标志 |= (cast(整数_)(节点标志_.不输出文件));
    程序声明_ 程序声明 = 获取源文件的程序声明(n);
    .合并程序集符号 = K.获取合并符号(程序声明.符号);
    .当前包名 = 合并程序集符号.碎裂名称;
    dstring ID = 获取符号文本Id(.合并程序集符号);
    if (!未整合的源文件组.具有(ID)) {
        未整合的源文件组.p·设置(ID, new 未整合的源文件_());
    }
    .当前未整合的源文件 = 未整合的源文件组.获取(ID);
    .当前打印环境 = new 类型打印环境_(类型打印标志_.加入未完成语句_ | 类型打印标志_.字面量提升_ | 类型打印标志_.枚举提升_, .当前未整合的源文件);
    初始当前打印环境(.当前打印环境);
    dstring 源文件Id = 获取节点文本Id(n);
    当前未整合的源文件.源文件组内索引.p·设置(源文件Id, 当前未整合的源文件.整合的文件.length);
    .追加!(源文件_)(当前未整合的源文件.整合的文件, n);
    当前未整合的源文件.程序名称 = 连接(.当前包名, "."d);
    访问节点数组!(基础节点_)(n.语句组, cast(void delegate(基础节点_))(·fd(&.访问程序集语句)));
    if (合并程序集符号.声明组.length == 当前未整合的源文件.整合的文件.length) {
        if (.输出的源文件 is ··null!(未整合的源文件_[])) {
            .输出的源文件 = 创建数组!(未整合的源文件_)();
        }
        .追加!(未整合的源文件_)(.输出的源文件, .当前未整合的源文件);
    }
}
void 访问程序集语句(基础节点_ n) {
    switch (n.目标种类) {
        case KSK.版本表达式语句: {
            return;
        }
        case KSK.版本语句: {
            return .访问版本语句((cast(版本语句_)(n)));
        }
        case KSK.程序声明: {
            return .访问程序声明((cast(程序声明_)(n)));
        }
        case KSK.测试单元语句: {
            return .访问测试单元语句((cast(测试单元语句_)(n)));
        }
        case KSK.块: {
            return .访问块语句((cast(块_)(n)));
        }
        case KSK.变量语句: {
            return .访问变量语句((cast(变量语句_)(n)));
        }
        case KSK.对象声明: {
            return .访问对象声明((cast(对象声明节点_)(n)));
        }
        case KSK.结构声明: {
            return .访问结构声明((cast(结构声明节点_)(n)));
        }
        case KSK.函数声明: {
            return .访问函数声明((cast(函数声明_)(n)));
        }
        default: break;
    }
}
void 访问版本语句(版本语句_ n) {
    ··klang类型_.节点扩展_ links = 获取节点扩展(n.表达式);
    if (links.计算的版本表达式 == 三元结果_.真_) {
        .访问程序集语句(n.然后语句);
    }
    else if (n.否则语句 !is ··null!(节点_)) {
        .访问程序集语句(n.否则语句);
    }
}
void 访问程序声明(程序声明_ n) {
    访问节点数组!(节点_)(n.语句组, cast(void delegate(节点_))(·fd(&.访问程序集语句)));
}
void 访问测试单元语句(测试单元语句_ n) {
    实例化测试单元(n);
}
void 访问块语句(块_ n) {
    访问节点数组!(节点_)(n.语句组, cast(void delegate(节点_))(·fd(&.访问程序集语句)));
}
void 访问变量语句(变量语句_ n) {
    .访问变量声明列表(n.声明列表);
}
void 访问变量声明列表(变量声明列表_ n) {
    访问节点数组!(变量声明_)(n.声明组, cast(void delegate(变量声明_))(·fd(&.访问变量声明)));
}
void 访问变量声明(变量声明_ n) {
    实例化全局变量声明(n);
}
void 访问结构声明(结构声明节点_ n) {
    if ((n.标志 & 节点标志_.是泛型声明_) == 0) {
        符号_ 符号 = 获取节点符号(n);
        ··klang类型_.Klang类型_ 声明类型 = K.获取符号的声明类型(符号);
        当前打印环境.当前类型 = 声明类型;
        实例化类型(声明类型, .当前打印环境);
    }
}
void 访问对象声明(对象声明节点_ n) {
    if ((n.标志 & 节点标志_.是泛型声明_) == 0) {
        符号_ 符号 = 获取节点符号(n);
        ··klang类型_.Klang类型_ 声明类型 = K.获取符号的声明类型(符号);
        当前打印环境.当前类型 = 声明类型;
        实例化类型(声明类型, .当前打印环境);
    }
}
void 访问函数声明(函数声明_ n) {
    if ((n.标志 & 节点标志_.是泛型声明_) == 0) {
        ··klang类型_.Klang类型_ 类型 = K.获取符号的类型(n.符号);
        ··klang类型_.Klang签名_ 签名 = K.获取签名从签名声明(n);
        当前打印环境.当前类型 = 类型;
        当前打印环境.当前类型.当前需要实例化的签名 = 签名;
        if (是启动函数(n)) {
            类型.实例化名称 = "_Dmain"d;
        }
        实例化类型(类型, .当前打印环境);
    }
}
void 清除语句前部分隔距离(基础节点_[] 语句组) {
    {
        for (int i = 0; i < 语句组.length; ++i) {
            基础节点_ sn = 语句组[i];
            if (sn.目标种类 == KSK.合成注释) {
                清除分隔距离(sn);
                continue;
            }
            return;
        }
    }
    return;
}
dstring 计算合成文件输出名() {
    dstring 输出目录 = "./输出"d;
    if ((cast(编译选项_)(.编译选项)).输出 !is ··null!(dstring)) {
        输出目录 = (cast(编译选项_)(.编译选项)).输出;
    }
    dstring 名称 = 编译选项.名称 ? 编译选项.名称 : "app"d;
    dstring 输出文件名 = 组合路径(主机.获取当前目录(), [输出目录, 名称 ~ "__泛型_.k2"d]);
    /*
    循环 (sys.文件存在(输出文件名)) {
        输出文件名 = 尝试删除扩展(输出文件名, ".k2");
        输出文件名 += "_.k2";
    }
    */
    return 输出文件名;
}
